#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "plugin.h"
#include "errno.h"

int plugin_server_run;
pthread_t plugin_server;

int plugin_connections = 0;
struct plugin_info plugin_list[PLUGIN_MAX_CONNECTION];

void *plugin_server_thread(void *arg) {
	struct plugin_info *info = &plugin_list[(int)arg];

	close(info->sock);
	return 0;
}

void *plugin_server_routine(void *arg) {
	int sock = (int)arg, sockconn;
	int i, ret, socksize;
	struct sockaddr_in sockaddr;

	while (plugin_server_run) {
		if ((sockconn = accept(sock, (struct sockaddr *)&sockaddr, &socksize)) == -1) {
			if (errno != EAGAIN && errno != EWOULDBLOCK) {
				fprintf(stderr, "chipmuck: error on accept(), errno=%d.\n", errno);
				break;
			}
		}
		else {
			i = plugin_connections;
			plugin_list[i].sock = sockconn;
			if ((ret = pthread_create(&plugin_list[i].thread, 0, plugin_server_thread, (void *)i)) != 0) {
				fprintf(stderr, "chipmuck: error on pthread_create(), errno=%d.\n", ret);
				close(sockconn);
			}
			else
				plugin_connections++;
		}
		usleep(200);
	}
	close(sock);

	while (plugin_server_run) {
		usleep(200);
	}
	return 0;
}

int plugin_listen() {
	int sock, ret;
	struct sockaddr_in sockaddr;

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		fprintf(stderr, "chipmuck: error on socket(), errno=%d.\n", errno);
		return E_NETWORK_ERROR;
	}

	if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) == -1) {
		fprintf(stderr, "chipmuck: error on fcntl(), errno=%d.\n", errno);
		ret = E_NETWORK_ERROR;
		goto err;
	}

	sockaddr.sin_family = AF_INET;
	sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	sockaddr.sin_port = htons(PLUGIN_PORT);
	if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1) {
		fprintf(stderr, "chipmuck: error on bind(), errno=%d.\n", errno);
		ret = E_NETWORK_ERROR;
		goto err;
	}

	if (listen(sock, 5) == -1) {
		fprintf(stderr, "chipmuck: error on listen(), errno=%d.\n", errno);
		ret = E_NETWORK_ERROR;
		goto err;
	}

	plugin_server_run = 1;
	if ((ret = pthread_create(&plugin_server, 0, plugin_server_routine, (void *)sock)) != 0) {
		fprintf(stderr, "chipmuck: error on pthread_create(), errno=%d.\n", ret);
		ret = E_PTHREAD_ERROR;
		goto err;
	}
	return 0;
err:
	close(sock);
	return ret;
}

void plugin_notice_breakpoint(int plugin_id, unsigned int *regs, int nreg) {
}

void plugin_notice_dump_memory(int plugin_id, int ret) {
}

void plugin_notice_add_breakpoint(int plugin_id, int ret) {
}

void plugin_notice_del_breakpoint(int plugin_id, int ret) {
}

void plugin_notice_halt(int plugin_id) {
}

int plugin_stopall() {
	plugin_server_run = 0;
	return 0;
}
